/** HSI and RGB functions
**
** @version: $Id: Colors.cpp 64 2010-11-25 20:46:39Z NeurobaticsTim@gmail.com $
*/
#define _USE_MATH_DEFINES
#include <math.h>

#include "Colors.h"


static const float cfRAD2DEG = (float)(180 / M_PI);
static const float cfDEG2RAD = (float)(M_PI / 180);


D3DXCOLOR CScale(float fScale, D3DXCOLOR cColor)
{
	return D3DXCOLOR(fScale * cColor.r, fScale * cColor.g, fScale * cColor.b, cColor.a);
}


/* Convert RGB to HSI */
HSICOLOR RGB2HSI(const D3DXCOLOR RGB)
{
	float R = RGB.r;
	float G = RGB.g;
	float B = RGB.b;
	float A = RGB.a;
	float H, S, I;

	/* compute theta */
	float numerator = ((R - G) + (R - B)) / 2.0f;
	float denominator = sqrt(((R - G) * (R - G)) + ((R - B) * (G - B)));
	float theta = acos(numerator / denominator) * cfRAD2DEG;

	/* H */
	H = (B > G) ? (360.0f - theta) : theta;

	/* I */
	I = (R + G + B) / 3.0f;

	/* S */
	S = 1.0f - (min(R, min(G, B)) / I);

	return HSICOLOR((float)(H / 360.0f), (float)S, (float)I, (float)A);
}

/* Convert HSI to RGB */
D3DXCOLOR HSI2RGB(const HSICOLOR HSI)
{
	float H = HSI.h * 360.0f;
	float S = HSI.s;
	float I = HSI.i;
	float A = HSI.a;
	float R, G, B;

	/* Temp values to be plugged-in later */
	#define T1(H,S,I)	(I * (1.0f - S))
	#define	T2(H,S,I)	(I * (1.0f + ((S * cosf(cfDEG2RAD * H)) / cosf(cfDEG2RAD * (60.0f - H)))))

	/* Check the three ranges */
	if ((0.0f < H) && (H <= 120.0f))
	{
		B = T1(H, S, I);
		R = T2(H, S, I);
		G = (3 * I) - (R + B);
	}
	else if ((120.0f <= H) && (H < 240.0f))
	{
		H -= 120.0f;
		R = T1(H, S, I);
		G = T2(H, S, I);
		B = (3 * I) - (R + G);
	}
	else
	{
		H -= 240.0f;
		G = T1(H, S, I);
		B = T2(H, S, I);
		R = (3 * I) - (G + B);
	}

	return D3DXCOLOR((float)R, (float)G, (float)B, (float)A);
}

/* Continuously change the color
**
** (use an increment of something like .002 for nice cycling)
*/
D3DXCOLOR CycleColor(const D3DXCOLOR RGB, const float fIncrement)
{
	/* Using HSI color space allows hue to be changed without changing
	** saturation or intensity
	*/
	HSICOLOR HSI = RGB2HSI(RGB);
	HSI.h += fIncrement;
	/* Only want the fractional part so subtract the integer part */
	HSI.h -= (float)((int)HSI.h);
	return HSI2RGB(HSI);
}
